/**
 @file sys_usw_ipfix.h

 @author  Copyright (C) 2013 Centec Networks Inc.  All rights reserved.

 @date 2013-10-17

 @version v3.0
*/
#ifndef _SYS_USW_IPFIX_H
#define _SYS_USW_IPFIX_H


/****************************************************************
 *
 * Header Files
 *
 ***************************************************************/
#include "ctc_const.h"
#include "ctc_ipfix.h"
#include "ctc_spool.h"
#include "ctc_macro.h"
#include "ctc_vector.h"
#include "sys_usw_common.h"

/****************************************************************
*
* Defines and Macros
*
****************************************************************/
#define SYS_IPFIX_MAX_SAMPLE_PROFILE 4
#define SYS_IPFIX_SHORT_MODE_NUM (256*1024)
#define SYS_IPFIX_UDF_A0_VALID 0x2
#define SYS_IPFIX_HASH_FIELD_NUM 16
#define SYS_IPFIX_MERGE_TYPE_VXLAN  1
#define SYS_IPFIX_MERGE_TYPE_GRE    2
#define SYS_IPFIX_MERGE_TYPE_WLAN 3
#define SYS_USW_DMA_INFO_OFFSET 12
#define SYS_IPFIX_MAX_EXPORT_ENTRY_NUM 1024
#define ARP_ETHER_TYPE 0x0806
#define IPV4_ETHER_TYPE 0x0800
#define SYS_IPFIX_SINGLE_KEY_SIZE DRV_TABLE_ENTRY_SIZE(lchip,DsIpfixL3Ipv4ShortHashKey_t)
#define SYS_IPFIX_DOUBLE_KEY_SIZE DRV_TABLE_ENTRY_SIZE(lchip,DsIpfixL2HashKey_t)
#define SYS_IPFIX_QUAD_KEY_SIZE DRV_TABLE_ENTRY_SIZE(lchip,DsIpfixL3Ipv6HashKey_t)
#define MAX_XKEY_FIELD_NUM 8
#define MAX_XDATA_FIELD_NUM 32

#define SYS_IPFIX_MAP_IP_FRAG(ctc_ip_frag) \
    (((ctc_ip_frag) == CTC_IP_FRAG_NOT_FIRST)?3:(((ctc_ip_frag) == CTC_IP_FRAG_SMALL)?2:(((ctc_ip_frag) == CTC_IP_FRAG_FIRST)?1:0)))
#define SYS_IPFIX_UNMAP_IP_FRAG(drv_ip_frag) \
    (((drv_ip_frag) == 3)? CTC_IP_FRAG_NOT_FIRST:(((drv_ip_frag) == 2)? CTC_IP_FRAG_SMALL:(((drv_ip_frag) == 1)? CTC_IP_FRAG_FIRST: CTC_IP_FRAG_NON)))
#define SYS_IPFIX_AD_INDEX(key_type, key_index) ()

#define SYS_TM_IPFIX_DECODE_METADATA(value) ((value) & 0x3FFF)
#define SYS_TM_IPFIX_ENCODE_METADATA(value) ((value) | 0x4000)
#define SYS_TMM_IPFIX_DECODE_METADATA(value) ((value) & 0x7FFF)
#define SYS_TMM_IPFIX_ENCODE_METADATA(value) ((value) | 0x8000)

typedef int32 (* p_sys_encode_cb_t)(uint8 lchip, ctc_ipfix_data_t* p_key, void* p_data);
typedef int32 (* p_sys_decode_cb_t)(uint8 lchip, ctc_ipfix_data_t* p_key, void* p_data);
typedef int32 (* p_sys_set_hashsel_cb_t)(uint8 lchip, ctc_ipfix_hash_field_sel_t* field_sel);
typedef int32 (* p_sys_get_hashsel_cb_t)(uint8 lchip, uint8 field_sel_id, ctc_ipfix_hash_field_sel_t* field_sel);

typedef struct sys_ipfix_kset_s {
    uint32 w[CTC_B2W_SIZE(CTC_FIELD_KEY_NUM)];
} sys_ipfix_kset_t;

struct sys_ipfix_master_s
{
    ctc_ipfix_fn_t ipfix_cb;
    uint32         max_ptr;
    uint32         aging_interval;
    uint32         export_interval;
    uint32         exp_cnt_stats[CTC_IPFIX_REASON_MAX];       /* statistics based export reason, refer to ctc_ipfix_export_reason_t */

    uint64         exp_pkt_cnt_stats[CTC_IPFIX_REASON_MAX];   /* statistics based export reason, refer to ctc_ipfix_export_reason_t */
    uint64         exp_pkt_byte_stats[CTC_IPFIX_REASON_MAX];  /* statistics based export reason, refer to ctc_ipfix_export_reason_t */
    void*          user_data;
    ctc_spool_t*   sample_spool;            /* data is sys_ipfix_sample_profile_t*/
    ctc_spool_t*   drop_classid_spool[CTC_BOTH_DIRECTION];      /* data is sys_ipfix_discard_classid_t*/
    uint32         sip_idx_bmp;
    uint32         sip_interval[CTC_BOTH_DIRECTION *SYS_IPFIX_MAX_SAMPLE_PROFILE];
    sal_mutex_t*   p_mutex;
    uint16 max_export_entry_num;
    uint8   decode_offset;
    uint8   short_mode  :1;
    uint8   ignore_drop_reason  :1;  /* TMM: global cfg, don't care drop reason when record drop cnt */ 
    uint8   rsv :6;
    uint32 dump_num;
    p_sys_encode_cb_t callbacks_encode[CTC_IPFIX_KEY_HASH_FLEX_BASE];/*encode key*/
    p_sys_decode_cb_t callbacks_decode[CTC_IPFIX_KEY_HASH_FLEX_BASE];/*decode key*/
    p_sys_set_hashsel_cb_t callbacks_set_hashsel[CTC_IPFIX_KEY_HASH_FLEX_BASE];/*set hash select*/
    p_sys_get_hashsel_cb_t callbacks_get_hashsel[CTC_IPFIX_KEY_HASH_FLEX_BASE];/*get hash select*/
    ctc_spool_t* xalu_spool;/*key is the xalu profile*/
    ctc_vector_t* xalu_vec;/*get the alu type and mode for decoding the xalu ad data*/
    ctc_vector_t* flex_key_vec;
    sys_ipfix_kset_t***     kset_db;/*all key type kset*/
    void* cb_buf;/*malloc ctc_ipfix_data_t pointer*/
    uint8 cb_buf_status;/*whether ipfix in export status*/
};
typedef struct sys_ipfix_master_s sys_ipfix_master_t;
extern sys_ipfix_master_t  *p_usw_ipfix_master[CTC_MAX_LOCAL_CHIP_NUM_PP];

#define SYS_IPFIX_MAX_SAMPLE_PROFILE 4

struct sys_ipfix_sample_profile_s
{
    uint16  interval;
    uint8   dir;
    uint8   mode;      /*bit0 sample mode, bit1 sample_type, refer to ctc_ipfix_flow_cfg_t*/

    uint16  ad_index;
};
typedef struct sys_ipfix_sample_profile_s sys_ipfix_sample_profile_t;

/**
 @brief  ipfix drop classid data structure
*/
struct sys_ipfix_drop_classid_s
{
    uint32  drop_reason;
    uint32  calc_key_len[0];

    ctc_spool_index_t index;
};
typedef struct sys_ipfix_drop_classid_s sys_ipfix_drop_classid_t;

struct sys_ipfix_xalu_profile_s
{
    DsIpfixAluProfile_m ds;
    uint32  calc_key_len[0];

    ctc_spool_index_t index;
};
typedef struct sys_ipfix_xalu_profile_s sys_ipfix_xalu_profile_t;

struct sys_ipfix_xalu_vec_s
{
    uint8 xalu_type[8];/*bit7 is mode, other bit0-6 is the alu type*/
};
typedef struct sys_ipfix_xalu_vec_s sys_ipfix_xalu_vec_t;

struct sys_ipfix_flexed_key_s
{
    uint32  key_type          :8;
    uint32  origin_key_type   :6;
    uint32  dir               :1;
    uint32  key_size          :15;
    uint32  mode              :2;
    ctc_ipfix_kset_t kset;
};
typedef struct sys_ipfix_flexed_key_s sys_ipfix_flexed_key_t;


#define IPFIX_IPV4_MASK(ip, len)                              \
{  \
    uint32 temp;  \
    temp = (ip) >> (31 - (len-1));  \
    (ip) = temp << (31 - (len-1));  \
}

#define IPFIX_IPV6_MASK(ip, len)                              \
    {                                                       \
        uint8 feedlen = CTC_IPV6_ADDR_LEN_IN_BIT - (len);   \
        uint8 sublen = feedlen % 32;                        \
        int8 index = feedlen / 32;                          \
        if (sublen)                                          \
        {                                                   \
            uint32 mask = ~((1 << sublen) - 1);             \
            (ip)[index] &= mask;                            \
            index--;                                        \
        }                                                   \
        for (; index > 0; index--)                          \
        {                                                   \
            (ip)[4-index] = 0;                                \
        }                                                   \
    }

#define SYS_IPFIX_CHECK_DIR(dir) \
    if ((dir) >= CTC_BOTH_DIRECTION) \
    { \
        return CTC_E_INVALID_PARAM; \
    }

#define IPFIX_IPV4_MASK_LEN_CHECK(len)         \
    {                                                 \
        if ((len > CTC_IPV4_ADDR_LEN_IN_BIT) || (len < 1)){  \
            return CTC_E_INVALID_PARAM; }               \
    }

#define IPFIX_IPV6_MASK_LEN_CHECK(len)         \
    {                                                 \
        if (len > CTC_IPV6_ADDR_LEN_IN_BIT){  \
            return CTC_E_INVALID_PARAM; }               \
    }

#define SYS_IPFIX_LOCK(lchip) \
    do                                       \
    {                                          \
        if(p_usw_ipfix_master[lchip]->p_mutex != NULL)\
        {                                            \
            sal_mutex_lock(p_usw_ipfix_master[lchip]->p_mutex);  \
        }                                                 \
    }while(0)

#define SYS_IPFIX_UNLOCK(lchip) \
    do               \
    {                                         \
        if(p_usw_ipfix_master[lchip]->p_mutex != NULL)\
        {                                          \
            sal_mutex_unlock(p_usw_ipfix_master[lchip]->p_mutex); \
        }                                                   \
    }while(0)

#define SYS_IPFIX_DBG_OUT(level,FMT, ...) \
    do{\
        CTC_DEBUG_OUT(ipfix, ipfix, IPFIX_SYS, level, FMT, ##__VA_ARGS__); \
    }while(0)
    
#define SYS_IPFIX_GET_TAB_BY_TYPE(key_type,dir) _sys_usw_ipfix_get_tbl_id_by_type(lchip, key_type,dir)
#define SYS_IPFIX_OP_DIR(dir) ((1 == MCHIP_CAP(SYS_CAP_IPFIX_MEMORY_SHARE))?2:dir)
#define SYS_IPFIX_GET_TABLE(tbl_id, dir) _sys_usw_ipfix_get_tbl_id_by_dir(lchip, tbl_id, dir)
#define SYS_IPFIX_GET_INDEX(index, dir) ((dir == CTC_INGRESS)?(index):(index - MCHIP_CAP(SYS_CAP_IPFIX_LONG_KEY_NUM)))
#define SYS_IPFIX_GET_ADINDEX(index, dir) ((dir == CTC_INGRESS)?(index):(index - MCHIP_CAP(SYS_CAP_IPFIX_AD_NUM)))

enum sys_ipfix_traverse_action_e
{
    SYS_IPFIX_DUMP_ENYRY_INFO = 0x0011,
};
typedef enum sys_ipfix_traverse_action_e sys_ipfix_traverse_action_t;

enum sys_ipfix_hash_type_e
{
    SYS_IPFIX_HASH_TYPE_INVALID                     = 0x0,
    SYS_IPFIX_HASH_TYPE_L2                          = 0x1,
    SYS_IPFIX_HASH_TYPE_L2L3                        = 0x2,
    SYS_IPFIX_HASH_TYPE_IPV4                        = 0x3,
    SYS_IPFIX_HASH_TYPE_IPV6                        = 0x4,
    SYS_IPFIX_HASH_TYPE_MPLS                        = 0x5,
    SYS_IPFIX_HASH_TYPE_IPV4_SHORT                  = 0x6,
    SYS_IPFIX_HASH_TYPE_IPV6_SHORT                  = 0x7,
    SYS_IPFIX_HASH_TYPE_UDF_SHORT                   = 0x8,
    SYS_IPFIX_HASH_TYPE_UDF                         = 0x9,
    SYS_IPFIX_HASH_TYPE_NSH                         = 0xa,
    SYS_IPFIX_HASH_TYPE_NSH_SHORT                   = 0xb,
};
typedef enum sys_ipfix_hash_type_e sys_ipfix_hash_type_t;

enum sys_ipfix_dest_type_e
{
    SYS_IPFIX_UNICAST_DEST=1,
    SYS_IPFIX_L2MC_DEST=2,
    SYS_IPFIX_L3MC_DEST=3,
    SYS_IPFIX_BCAST_DEST=4,
    SYS_IPFIX_UNKNOW_PKT_DEST=5,
    SYS_IPFIX_UNION_DEST = 6, /*in TMM later chip, means aps group*/
    SYS_IPFIX_OTHER_MCAST = 7,
    SYS_IPFIX_APS_DEST=6,
    SYS_IPFIX_ECMP_DEST=8,
    SYS_IPFIX_LAG_DEST=9,
    SYS_IPFIX_CPU_DEST=10,
};
typedef enum sys_ipfix_dest_type_e sys_ipfix_dest_type_t;

enum sys_ipfix_sub_dest_type_e
{
    SYS_IPFIX_SUB_APS_DEST=0,
    SYS_IPFIX_SUB_ECMP_DEST,
    SYS_IPFIX_SUB_LINKAGG_DEST,
    SYS_IPFIX_SUB_CPU_DEST
};
typedef enum sys_ipfix_sub_dest_type_e sys_ipfix_sub_dest_type_t;

#define SYS_IPFIX_MAX_IP_MASK_LEN 31
#define SYS_IPFIX_BUF_MAX     32
#define IPFIX_SET_HW_IP6(d, s)    SYS_USW_REVERT_IP6(d, s)

enum sys_ipfix_export_reason_e
{
    SYS_IPFIX_EXPORTREASON_NO_EXPORT,
    SYS_IPFIX_EXPORTREASON_EXPIRED,
    SYS_IPFIX_EXPORTREASON_TCP_SESSION_CLOSE,
    SYS_IPFIX_EXPORTREASON_PACKET_COUNT_OVERFLOW  ,
    SYS_IPFIX_EXPORTREASON_BYTE_COUNT_OVERFLOW ,
    SYS_IPFIX_EXPORTREASON_NEW_FLOW_EXPORT   ,
    SYS_IPFIX_EXPORTREASON_DESTINATION_CHANGE   ,
    SYS_IPFIX_EXPORTREASON_TS_COUNT_OVERFLOW,
    SYS_IPFIX_EXPORTREASON_JITTER_OVERFLOW,
    SYS_IPFIX_EXPORTREASON_LATENCY_OVERFLOW,
    SYS_IPFIX_EXPORTREASON_TTL_CHANGE,
    SYS_IPFIX_EXPORTREASON_DROP_PKT_COUNT_OVERFLOW,
    SYS_IPFIX_EXPORTREASON_BUFFER_DROP_OVERFLOW = 20,
    SYS_IPFIX_EXPORTREASON_LATENCY_DROP_OVERFLOW = 21,
};

typedef enum sys_ipfix_export_reason_e sys_ipfix_export_reason_t;

enum sys_ipfix_alu_type_e
{
    SYS_IPFIX_ALU_TYPE_BURST=0,
    SYS_IPFIX_ALU_TYPE_LATENCY
};
typedef enum sys_ipfix_alu_type_e sys_ipfix_alu_type_t;

struct sys_ipfix_param_s
{
    ctc_ipfix_data_t* p_key;
    ds_t key_data;
    ds_t igr_ad_data;
    ds_t egs_ad_data;
};
typedef struct sys_ipfix_param_s sys_ipfix_param_t;


/****************************************************************************
 *
* Function
*
*****************************************************************************/
extern int32
sys_usw_ipfix_init(uint8 lchip, void* p_global_cfg);
extern int32
sys_usw_ipfix_cb_init(uint8 lchip);
extern int32
sys_usw_ipfix_sync_data(uint8 lchip, void* p_dma_info);
extern int32
sys_usw_ipfix_set_hash_field_sel(uint8 lchip, ctc_ipfix_hash_field_sel_t* field_sel);
extern int32
sys_usw_ipfix_set_global_cfg(uint8 lchip, ctc_ipfix_global_cfg_t *ipfix_cfg);
extern int32
sys_usw_ipfix_get_global_cfg(uint8 lchip, ctc_ipfix_global_cfg_t *ipfix_cfg);
extern int32
sys_usw_ipfix_set_flow_cfg(uint8 lchip, ctc_ipfix_flow_cfg_t* flow_cfg);
extern int32
sys_usw_ipfix_get_flow_cfg(uint8 lchip, ctc_ipfix_flow_cfg_t* flow_cfg);
extern int32
sys_usw_ipfix_register_cb(uint8 lchip, ctc_ipfix_fn_t callback,void *userdata);
#if 0
int32
sys_usw_ipfix_get_cb(uint8 lchip, void **cb, void** user_data);
#endif
extern int32
sys_usw_ipfix_get_entry_by_key(uint8 lchip, ctc_ipfix_data_t* p_key, uint32* p_rst_hit, uint32* p_rst_key_index);
extern int32
sys_usw_ipfix_add_entry_by_key(uint8 lchip, ctc_ipfix_data_t* p_key);
extern int32
sys_usw_ipfix_add_entry_by_index(uint8 lchip, ctc_ipfix_data_t* p_key, uint32 index);
extern int32
sys_usw_ipfix_add_ad_by_index(uint8 lchip, ctc_ipfix_data_t* p_key, uint32 index);
extern int32
sys_usw_ipfix_delete_ad_by_index(uint8 lchip, uint32 index, uint8 dir);
extern int32
sys_usw_ipfix_delete_entry_by_index(uint8 lchip, uint8 type, uint32 index, uint8 dir);
extern int32
sys_usw_ipfix_delete_entry(uint8 lchip, ctc_ipfix_data_t* p_key);
extern int32
sys_usw_ipfix_delete_entry_by_key(uint8 lchip, ctc_ipfix_data_t* p_key);
extern uint32
sys_usw_ipfix_get_flow_cnt(uint8 lchip);
extern int32
sys_usw_ipfix_get_ad_by_index(uint8 lchip, uint32 index, ctc_ipfix_data_t* p_out);
extern int32
sys_usw_ipfix_get_entry_by_index(uint8 lchip, uint32 index, uint8 dir, uint8 key_type, ctc_ipfix_data_t* p_out);
extern int32
sys_usw_ipfix_traverse(uint8 lchip, void* fn, ctc_ipfix_traverse_t* p_data, uint8 is_remove);
extern int32
sys_usw_ipfix_show_status(uint8 lchip, void *user_data);
extern int32
sys_usw_ipfix_show_stats(uint8 lchip, void *user_data, uint8 is_dump_db, sal_file_t p_f);
extern int32
sys_usw_ipfix_clear_stats(uint8 lchip, void * user_data);
extern int32
sys_usw_ipfix_set_short_key_mode(uint8 lchip, uint8 enable);
extern int32
sys_usw_ipfix_show_entry_info(ctc_ipfix_data_t* p_info, void* user_data);
extern int32
_sys_usw_ipfix_export_stats(uint8 lchip, uint8 exp_reason, uint64 pkt_cnt, uint64 byte_cnt);
extern int32
sys_usw_ipfix_deinit(uint8 lchip);
extern int32
sys_usw_ipfix_get_hash_field_sel(uint8 lchip, uint8 field_sel_id, uint8 key_type, ctc_ipfix_hash_field_sel_t* field_sel);
extern int32
sys_usw_ipfix_set_property(uint8 lchip, ctc_ipfix_property_t* p_ipfix_pro);
extern int32
sys_usw_ipfix_get_property(uint8 lchip, ctc_ipfix_property_t* p_ipfix_pro);
extern int32
sys_usw_ipfix_set_flex_key_fields(uint8 lchip, ctc_ipfix_flex_key_t* ipfix_flex_key);
extern int32
sys_usw_ipfix_get_flex_key_fields(uint8 lchip, ctc_ipfix_flex_key_t* ipfix_flex_key);
extern int32
sys_usw_ipfix_get_flex_key_sets(uint8 lchip, ctc_ipfix_flex_key_t* ipfix_flex_key);

#endif
